package com.ganinfo.common.geo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;

/**
 * 地理坐标工具类
 * 
 * @author karl 2015年12月18日
 */
public class GeoUtil {

	/**
	 * 根据经纬度计算两点间距离
	 * 
	 * @param lon1
	 *            第一点经度
	 * @param lat1
	 *            第一点纬度
	 * @param lon2
	 *            第二点经度
	 * @param lat2
	 *            第二点纬度
	 * @return
	 */
	public static double getLonLatDistance(double lon1, double lat1,
			double lon2, double lat2) {
		double res = -1;
		// 非法经纬度判断,经度须在【-180~180】之间，纬度须在【-90~90】之间。
		if (!(isCorrectLonLat(lon1, lat1) && isCorrectLonLat(lon2, lat2))) {
			return res;
		}
		double radLat1 = Math.toRadians(lat1);
		double radLat2 = Math.toRadians(lat2);
		double a = radLat1 - radLat2;
		double b = Math.toRadians(lon1) - Math.toRadians(lon2);
		res = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
				+ Math.cos(radLat1) * Math.cos(radLat2)
				* Math.pow(Math.sin(b / 2), 2)));
		res = res * 6378137.0;// 取WGS84标准参考椭球中的地球长半径(单位:m)
		res = Math.round(res * 10000) / 10000;
		return res;
	}

	/**
	 * 经纬度坐标转换墨卡托
	 * 
	 * @param lon
	 *            经度
	 * @param lat
	 *            纬度
	 * @return
	 */
	public static double[] lonLat2Mercator(double lon, double lat) {
		double[] xy = new double[2];
		// 非法经纬度判断，。
		if (!isCorrectLonLat(lon, lat)) {
			xy[0] = 0;
			xy[1] = 0;
			return xy;
		}
		double x = lon * 20037508.342789 / 180;
		double y = Math.log(Math.tan((90 + lat) * Math.PI / 360))
				/ (Math.PI / 180);
		y = y * 20037508.34789 / 180;

		x = shortDoubleValue(x, 3);
		y = shortDoubleValue(y, 3);
		xy[0] = x;
		xy[1] = y;
		return xy;
	}

	/**
	 * 墨卡托坐标转换经纬度
	 * 
	 * @param mercatorX
	 * @param mercatorY
	 * @return
	 */
	public static double[] mercator2LonLat(double mercatorX, double mercatorY) {
		double[] xy = new double[2];
		double x = mercatorX / 20037508.34 * 180;
		double y = mercatorY / 20037508.34 * 180;
		y = 180 / Math.PI
				* (2 * Math.atan(Math.exp(y * Math.PI / 180)) - Math.PI / 2);
		xy[0] = x;
		xy[1] = y;
		return xy;
	}

	/**
	 * 经纬度坐标是否合法。经度须在【-180~180】之间，纬度须在【-90~90】之间
	 * 
	 * @param lon
	 *            经度
	 * @param lat
	 *            纬度
	 * @return
	 */
	public static boolean isCorrectLonLat(Double lon, Double lat) {
		boolean flag = false;
		if (lon != null && lat != null && lon > -180 && lon < 180 && lat > -90
				&& lat < 90) {
			flag = true;
		}
		return flag;
	}

	/**
	 * 将米制单位距离转换为合适的字符串
	 * 
	 * @param dis
	 * @return
	 */
	public static String getDistanceStr(Double dis) {
		String res = "";
		if (dis == null || dis < 0) {
			res = "距离未知";
		} else {
			if (dis < 100) {
				res = "小于100米";
			} else if (dis >= 100 && dis < 1000) {
				dis = shortDoubleValue(dis, 1);
				res = (int) dis.doubleValue() + " 米";
			} else if (dis >= 1000) {
				// 四舍五入保留一位小数
				dis = shortDoubleValue(dis / 1000, 1);
				res = dis + " 公里";
			}
		}
		return res;
	}

	/**
	 * Double数据四舍五入保留小数
	 * 
	 * @param val
	 * @param scale
	 * @return
	 */
	private static Double shortDoubleValue(Double val, int scale) {
		Double res = 0.0;
		if (scale < 1) {
			scale = 1;
		}
		BigDecimal b = new BigDecimal(val);
		res = b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
		return res;
	}

	/**
	 * 将度分秒的经纬度转换为小数点
	 * 
	 * @param lonlat
	 * @return
	 */
	public static Double transformLonLat(String lonlat) {
		Double d = 0d;
		// 格式为116°20'4"
		if (lonlat.indexOf("°") > 0 || lonlat.indexOf("'") > 0
				|| lonlat.indexOf("\"") > 0) {
			if (lonlat.contains("°")) {
				d += Double.valueOf(lonlat.split("°")[0]);
			}
			if (lonlat.contains("'")) {
				d += Double.valueOf(lonlat.split("°")[1].split("'")[0]) / 60.0;
			}
			if (lonlat.contains("\"")) {
				d += Double.valueOf(lonlat.split("°")[1].split("'")[1]
						.split("\"")[0]) / 60.0 / 60.0;
			}
		}// 不是度分秒
		else {
			d = Double.valueOf(lonlat);
		}
		return d;
	}

	/**
	 * @Title: getCoordinate
	 * @Description: 根据具体位置获取经纬度(百度)
	 * @param addr
	 * @return 数组的第1个为经度。第2个为纬度
	 * @return: String[]
	 */
	public static String[] getLonLatFromAddressBaidu(String addr) {
		String lng = null;// 经度
		String lat = null;// 纬度
		String address = null;
		try {
			address = java.net.URLEncoder.encode(addr, "UTF-8");
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		String key = "f247cdb592eb43ebac6ccd27f796e2d2";
		String url = String
				.format("http://api.map.baidu.com/geocoder?address=%s&output=json&key=%s",
						address, key);
		URL myURL = null;
		URLConnection httpsConn = null;
		try {
			myURL = new URL(url);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		InputStreamReader insr = null;
		BufferedReader br = null;
		try {
			httpsConn = (URLConnection) myURL.openConnection();// 不使用代理
			if (httpsConn != null) {
				insr = new InputStreamReader(httpsConn.getInputStream(),
						"UTF-8");
				br = new BufferedReader(insr);
				String data = null;
				int count = 1;
				while ((data = br.readLine()) != null) {
					if (count == 5) {
						lng = (String) data.subSequence(data.indexOf(":") + 1,
								data.indexOf(","));// 经度
						count++;
					} else if (count == 6) {
						lat = data.substring(data.indexOf(":") + 1);// 纬度
						count++;
					} else {
						count++;
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (insr != null) {
				try {
					insr.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return new String[] { lng, lat };
	}

	/**
	 * @Title:       getAddressFromLonLat
	 * @Description: 根据经纬度获取城市信息(baidu)
	 * @param lon 纬度
	 * @param lng 经度
	 * @return  {"status":0,"result":{"location":{"lng":112.76535000506,"lat":22.754240005123},"formatted_address":"广东省佛山市高明区X492","business":"","addressComponent":{"city":"佛山市","country":"中国","direction":"","distance":"","district":"高明区","province":"广东省","street":"X492","street_number":"","country_code":0},"pois":[{"addr":"佛山市高明区","cp":"NavInfo","direction":"东北","distance":"680","name":"皂幕山泉","poiType":"公司企业","point":{"x":112.76102978437,"y":22.750226120112},"tag":"公司企业","tel":"","uid":"ea4a3dc9e82219534e5547fc","zip":""},{"addr":"四九二县道井头圩附近","cp":"NavInfo","direction":"东北","distance":"690","name":"乡下酒楼","poiType":"美食","point":{"x":112.76288029372,"y":22.748959622733},"tag":"美食;中餐厅","tel":"","uid":"b292b3aa9bf25c28be48422f","zip":""},{"addr":"四九二县道井头村附近","cp":"NavInfo","direction":"东北","distance":"724","name":"雄英酒楼","poiType":"美食","point":{"x":112.76211673404,"y":22.74900128402},"tag":"美食;中餐厅","tel":"","uid":"abe37f62d7e119b6cd04efd2","zip":""},{"addr":"四九二县道井头村附近","cp":"NavInfo","direction":"东北","distance":"730","name":"名峰酒楼","poiType":"美食","point":{"x":112.75995181776,"y":22.750776042908},"tag":"美食;中餐厅","tel":"","uid":"2fb890627b93c3a7c91b95e2","zip":""},{"addr":"杨和镇","cp":"NavInfo","direction":"东北","distance":"757","name":"山村菜馆","poiType":"美食","point":{"x":112.76165859823,"y":22.748934625955},"tag":"美食;中餐厅","tel":"","uid":"637df60ac6f49c7241afe68b","zip":""}],"poiRegions":[],"sematic_description":"皂幕山泉东北680米","cityCode":138}}
	 * @return:      String
	 */
	public static String getAddressFromLonLatBaidu(String lon,String lng) {
		String city = "";
		String url2 = "http://api.map.baidu.com/geocoder/v2/?ak=Ta3RZl7tsuNCmlO1zPUlNLbC&location="+lng+","+lon+"&output=json&pois=1 ";
		URL myURL2 = null;
		URLConnection httpsConn2 = null;
		try {
			myURL2 = new URL(url2);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		InputStreamReader insr2 = null;
		BufferedReader br2 = null;
		try {
			httpsConn2 = (URLConnection) myURL2.openConnection();// 不使用代理
			if (httpsConn2 != null) {
				insr2 = new InputStreamReader(httpsConn2.getInputStream(),
						"UTF-8");
				br2 = new BufferedReader(insr2);
				String data2 = br2.readLine();
				try {
					// 解析得到的json格式数据
					JSONObject dataJson=JSONObject.parseObject(data2);
					JSONObject result = dataJson.getJSONObject("result");
					JSONObject addressComponent = result.getJSONObject("addressComponent");
					city = addressComponent.getString("city");
				} catch (JSONException e) {
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (insr2 != null) {
				try {
					insr2.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (br2 != null) {
				try {
					br2.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return city;
	}
	
	public static void main(String[] args) {
		//http://restapi.amap.com/v3/geocode/geo?key=6812fba9cfd590b2def1ee6efbd67710&s=rsv3&city=35&address=福建省霞浦县水门畲族乡
		//String[] lonLatFromAddress = GeoUtil.getLonLatFromAddress("河北省沧州市沧县高川乡高川村");
		//System.out.println("*****"+GeoUtil.getAddressFromLonLat(lonLatFromAddress[1], lonLatFromAddress[0]));
	}
}
